home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / mfsm-1.1 / mfsm.c < prev    next >
C/C++ Source or Header  |  1995-06-23  |  49KB  |  1,708 lines

  1. /**
  2.  
  3.                    Motif File System Monitor - V 1.1
  4.  
  5.                                  by
  6.  
  7.                  SDH EngSoft
  8.                            (Shane D. Hill)
  9.    +-------------------------------------------------------------------+
  10.    | Copyright 1995 by Shane D. Hill (Shane.Hill@dsto.defence.gov.au)  |
  11.    |                                                                   |
  12.    | Permission to use, copy, modify, and to distribute this software  |
  13.    | and its documentation for any purpose is hereby granted without   |
  14.    | fee, provided that the above copyright notice appear in all       |
  15.    | copies and that both that copyright notice and this permission    |
  16.    | notice appear in supporting documentation.  There is no           |
  17.    | representations about the suitability of this software for        |
  18.    | any purpose.  this software is provided "as is" without express   |
  19.    | or implied warranty.                                              |
  20.    |                                                                   |
  21.    +-------------------------------------------------------------------+
  22.    **/
  23.  
  24. /**
  25.   C Includes
  26.   **/
  27. #include <ctype.h>
  28. #include <stdarg.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <unistd.h>
  33.  
  34. /**
  35.   Motif Includes
  36.   **/
  37. #include <Xm/CascadeB.h>
  38. #include <Xm/DialogS.h>
  39. #include <Xm/DrawingA.h>
  40. #include <Xm/DrawnB.h>
  41. #include <Xm/Form.h>
  42. #include <Xm/Frame.h>
  43. #include <Xm/Label.h>
  44. #include <Xm/PanedW.h>
  45. #include <Xm/PushB.h>
  46. #include <Xm/RowColumn.h>
  47. #include <Xm/Separator.h>
  48. #include <Xm/Text.h>
  49. #include <Xm/ToggleB.h>
  50.  
  51. #include <Xm/MwmUtil.h>
  52.  
  53. /**
  54.   System Includes
  55.   **/
  56. #include <errno.h>
  57. #include <pwd.h>
  58. #include <sys/types.h>
  59. #if defined(LINUX) || defined(SUNOS) || defined(HPUX)
  60. #  include <sys/vfs.h>
  61. #elif defined(SOLARIS)
  62. #  include <sys/statvfs.h>
  63. #elif defined(DIGITAL_UNIX)
  64. #  include <sys/mount.h>
  65. #else
  66. #  include <sys/statfs.h>
  67. #endif
  68.  
  69. #ifdef HAVE_QUOTAS
  70. #  if defined(AIX)
  71. #    include <jfs/quota.h>
  72. #  elif defined(DIGITAL_UNIX) || defined(SUNOS)
  73. #    include <ufs/quota.h> /** ufs is for SunOS 4.1.3 **/
  74. /** #    include <sys/fs/sfs_quota.h> /** sfs is for SVR4.2 **/
  75. #  elif defined(SOLARIS)
  76. #    include <sys/fs/ufs_quota.h>
  77. #  else
  78. #   include <sys/quota.h>
  79. #  endif
  80. #endif /** HAVE QUOTAS **/
  81.  
  82. #ifdef USE_IOCTL
  83. #  include <fcntl.h>
  84. #endif
  85.  
  86. /**
  87.   XPM Library & Pixmaps
  88.   **/
  89. #ifdef HAVE_XPM
  90. #  include "xpm.h"
  91. #  include "bitmaps/floppydrive.xpm"
  92. #  include "bitmaps/diskdrive.xpm"
  93. #  include "bitmaps/netdrive.xpm"
  94. #  include "bitmaps/user.xpm"
  95. #  include "bitmaps/bell.xpm"
  96. #  include "bitmaps/nobell.xpm"
  97. #  include "bitmaps/mouse_help.xpm"
  98. #  include "bitmaps/about_mfsm.xpm"
  99. #  include "bitmaps/icon.xpm"
  100. #endif
  101.  
  102. /**
  103.   X11 Bitmaps
  104.   **/
  105. #include "bitmaps/floppydrive.xbm"
  106. #include "bitmaps/diskdrive.xbm"
  107. #include "bitmaps/netdrive.xbm"
  108. #include "bitmaps/user.xbm"
  109. #include "bitmaps/bell.xbm"
  110. #include "bitmaps/nobell.xbm"
  111. #include "bitmaps/mouse_help.xbm"
  112. #include "bitmaps/about_mfsm.xbm"
  113. #include "bitmaps/icon.xbm"
  114.  
  115.  
  116. enum { FLOPPY_DISK,
  117.        HARD_DISK,
  118.        NETWORK_DISK,
  119.        USER,
  120.        BELL,
  121.        NOBELL,
  122.        MOUSE_HELP,
  123.        CDROM
  124. };
  125.  
  126. enum { ABOUT,
  127.        ICONIC
  128. };
  129.  
  130. enum { SYSTEM_SPACE,
  131.        QUOTA_SPACE
  132. };
  133.  
  134. #ifdef HAVE_XPM
  135. typedef struct icon_data {
  136.     Pixmap pixmap;
  137.     char **xpm_data;
  138.     char  *bm_bits;
  139.     int    bm_width;
  140.     int    bm_height;
  141.     int    mask;
  142. } ICONS;
  143. #else
  144. typedef struct icon_data {
  145.     Pixmap pixmap;
  146.     char  *bm_bits;
  147.     int    bm_width;
  148.     int    bm_height;
  149.     int    mask;
  150. } ICONS;
  151. #endif
  152.  
  153.  
  154. #ifdef HAVE_XPM
  155. ICONS icon_list[] = {
  156.     { 0, floppydrive_xpm,
  157.       floppydrive_bits, floppydrive_width, floppydrive_height, False},
  158.     { 0, diskdrive_xpm,
  159.       diskdrive_bits, diskdrive_width, diskdrive_height, False},
  160.     { 0, netdrive_xpm,
  161.       netdrive_bits, netdrive_width, netdrive_height, False},
  162.     { 0, user_xpm,
  163.       user_bits, user_width, user_height, False},
  164.     { 0, bell_xpm,
  165.       bell_bits, bell_width, bell_height, True},
  166.     { 0, nobell_xpm,
  167.       nobell_bits, nobell_width, nobell_height, True},
  168.     { 0, mouse_help_xpm,
  169.       mouse_help_bits, mouse_help_width, mouse_help_height, True},
  170.     NULL
  171. };
  172. ICONS mfsm_icons[] = {
  173.     { 0, about_mfsm_xpm,
  174.       about_mfsm_bits, about_mfsm_width, about_mfsm_height, False},
  175.     { 0, icon_xpm,
  176.       icon_bits, icon_width, icon_height, False},
  177.     NULL
  178. };
  179. #else
  180. ICONS icon_list[] = {
  181.     { 0, floppydrive_bits, floppydrive_width, floppydrive_height, False},
  182.     { 0, diskdrive_bits, diskdrive_width, diskdrive_height, False},
  183.     { 0, netdrive_bits, netdrive_width, netdrive_height, False},
  184.     { 0, user_bits, user_width, user_height, False},
  185.     { 0, bell_bits, bell_width, bell_height, True},
  186.     { 0, nobell_bits, nobell_width, nobell_height, True},
  187.     { 0, mouse_help_bits, mouse_help_width, mouse_help_height, True},
  188.     NULL
  189. };
  190. ICONS mfsm_icons[] = {
  191.     { 0, about_mfsm_bits, about_mfsm_width, about_mfsm_height},
  192.     { 0, icon_bits, icon_width, icon_height},
  193.     NULL
  194. };
  195. #endif
  196.  
  197. typedef struct drivebar_data {
  198.   char     *name;
  199.   char     *dev;
  200.   char     *path;
  201.   int       type;
  202.   int       userid;
  203.   Widget    widget;
  204.   Widget    usagebar;
  205.   GC        gc;
  206.   Pixmap    pixmap;
  207.   Dimension width;
  208.   Dimension height;
  209.   float     mbytes;
  210.   int       usage;
  211.   int       usage_type;
  212.   Widget    bell_toggle;
  213.   int       bell;
  214.   int       bell_activated;
  215.   struct drivebar_data *next;
  216. } DRIVE_BAR;
  217.  
  218. /**
  219. DRIVE_BAR drivebar_test[] = {
  220.     { "/tmp2", FLOPPY_DISK,  NULL, NULL, 0, NULL, 0, 0, 0.7,  50},
  221.     { "/home", HARD_DISK,    NULL, NULL, 0, NULL, 0, 0, 52.6, 25},
  222.     { "/tmp",  NETWORK_DISK, NULL, NULL, 0, NULL, 0, 0, 16.2, 86},
  223.     { "/home/hills",  USER, NULL, NULL, 0, NULL, 0, 0, 156.2, 32},
  224.     NULL
  225. };
  226. **/
  227.  
  228. enum { GREEN_ALERT,
  229.        YELLOW_ALERT,
  230.        RED_ALERT
  231. };
  232.     
  233.  
  234. typedef struct _menu_item {
  235.     char        *label;          /* the label for the item */
  236.     WidgetClass *class;          /* pushbutton, label, separator... */
  237.     Widget       *widget;        /* pointer to widget */
  238.     char         mnemonic;       /* mnemonic; '\0' if none */
  239.     char        *accelerator;    /* accelerator; NULL if none */
  240.     char        *accel_text;     /* to be converted to compound string */
  241.     char         enabled;        /* If menu item is enabled */
  242.     void       (*callback)();    /* routine to call; NULL if none */
  243.     XtPointer    callback_data;  /* client_data for callback() */
  244.     struct _menu_item *subitems; /* pullright menu items, if not NULL */
  245. } MenuItem;
  246.  
  247.  
  248. String fallbacks[] = {
  249.     "Mfsm*background: grey50",
  250.     "Mfsm*fontList:  -adobe-helvetica-bold-r-normal-*-*-100-*-*-*-*-*-*",
  251.     /** "Mfsm*foreground: black", **/
  252.     "Mfsm*drive.marginHeight: 5",
  253.     "Mfsm*drive.marginWidth:  5",
  254.     "Mfsm*usageBar.background: grey50",
  255.     "Mfsm*usageBar.borderWidth:    0",
  256.     "Mfsm*text.fontList: -adobe-helvetica-medium-r-normal-*-*-100-*-*-*-*-*-*",
  257.     "Mfsm*text.foreground: white",
  258.     "Mfsm*text.marginHeight: 0",
  259.     "Mfsm*text.marginWidth:  5",
  260.     "Mfsm*frame.shadowThickness: 2",
  261.     "Mfsm*_popup*background: deepskyblue4",
  262.     "Mfsm*_popup*foreground: white",
  263.     "Mfsm*About Mfsm*background: lightpink4",
  264.     "Mfsm*About Mfsm*foreground: yellow",
  265.     "Mfsm*about_text*highlightThickness: 0",
  266.     NULL
  267. };
  268.  
  269.  
  270. /* Resrcs is an object that contains "global variables" that we want the
  271.  * user to be able to initialize through resources or command line options.
  272.  * XtAppInitialize() initializes the fields in this data structure to values
  273.  * indicated by the XrmOptionsDescRec structure defined later.
  274.  */
  275. struct _resrcs {
  276.     XFontStruct *font;          /** font to use for bitmap labels **/
  277.     float        interval;      /** update interval in seconds **/
  278.     float        bell_interval; /** update interval in seconds **/
  279.     int          width;         /** width of usagebar **/
  280.     Pixel        ga_color;      /** green alert color **/
  281.     Pixel        ya_color;      /** yellow alert color **/
  282.     Pixel        ra_color;      /** red alert color **/
  283.     Pixel        pa_color;      /** panic alert color **/
  284.     int          yellow_alert;  /** yellow alert limit **/
  285.     int          red_alert;     /** red alert limit **/
  286.     int          panic_alert;   /** panic alert limit **/
  287.     int          show_all;      /** flag: select all drives **/
  288.     int          show_titlebar; /** flag: title bar display **/
  289.     int          show_diskused; /** flag: show disk used, not free **/
  290.     int          verbose;       /** flag: verbose comments **/
  291.     char        *filesystem;    /** list of file systems to monitor **/
  292. } Resrcs;
  293.  
  294.  
  295. /* .Xdefaults or app-defaults resources.  The values listed here (the last
  296.  * field in each structure) are used as the default values for the fields
  297.  * in the Resrcs struct above.
  298.  */
  299. static XtResource resources[] = {
  300.     { XmNfont, XmCFont, XmRFontStruct, sizeof(XFontStruct *),
  301.         XtOffsetOf( struct _resrcs, font), XmRString, "8x13" },
  302.     { "interval", "Interval", XmRFloat, sizeof( float),
  303.         XtOffsetOf( struct _resrcs, interval), XmRString, "1.0"},
  304.     { "bellInterval", "BellInterval", XmRFloat, sizeof( float),
  305.         XtOffsetOf( struct _resrcs, bell_interval), XmRString, "1.0"},
  306.     { "greenAlertColor", "GreenAlertColor", XmRPixel, sizeof( Pixel),
  307.         XtOffsetOf( struct _resrcs, ga_color), XmRString, "green"},
  308.     { "yellowAlertColor", "YellowAlertColor", XmRPixel, sizeof ( Pixel),
  309.         XtOffsetOf( struct _resrcs, ya_color), XmRString, "yellow"},
  310.     { "redAlertColor", "RedAlertColor", XmRPixel, sizeof( Pixel),
  311.         XtOffsetOf( struct _resrcs, ra_color), XmRString, "red"},
  312.     { "panicAlertColor", "PanicAlertColor", XmRPixel, sizeof( Pixel),
  313.         XtOffsetOf( struct _resrcs, pa_color), XmRString, "gold3"},
  314.     { "panicAlertLimit", "PanicAlertLimit", XmRInt, sizeof( int),
  315.         XtOffsetOf( struct _resrcs, panic_alert), XmRImmediate, (char *)99},
  316.     { "redAlertLimit", "redAlertLimit", XmRInt, sizeof( int),
  317.         XtOffsetOf( struct _resrcs, red_alert), XmRImmediate, (char *)95},
  318.     { "yellowAlertLimit", "YellowAlertLimit", XmRInt, sizeof( int),
  319.         XtOffsetOf( struct _resrcs, yellow_alert), XmRImmediate, (char *)75},
  320.     { "showAllDrives", "ShowAllDrives", XmRBoolean, sizeof( int),
  321.         XtOffsetOf( struct _resrcs, show_all), XmRImmediate, False},
  322.     { "fileSystem", "FileSystem", XmRString, sizeof(char *),
  323.         XtOffsetOf( struct _resrcs, filesystem), XmRString, "" },
  324.     { "verbose", "Verbose", XmRBoolean, sizeof( int),
  325.         XtOffsetOf( struct _resrcs, verbose), XmRImmediate, (char *)False},
  326.     { "usageBarWidth", "UsageBarWidth", XmRInt, sizeof( int),
  327.         XtOffsetOf( struct _resrcs, width), XmRImmediate, (char *)400},
  328.     { "showTitleBar", "ShowTitleBar", XmRBoolean, sizeof( int),
  329.         XtOffsetOf( struct _resrcs, show_titlebar), XmRImmediate,(char *)True},
  330.     { "showDiskUsed", "ShowDiskUsed", XmRBoolean, sizeof( int),
  331.         XtOffsetOf( struct _resrcs, show_diskused), XmRImmediate,(char *)False},
  332. };
  333.  
  334. /* If the following command line args (1st field) are found, set the
  335.  * associated resource values (2rnd field) to the given value (4th field).
  336.  */
  337. static XrmOptionDescRec options[] = {
  338.     { "-a", "showAllDrives", XrmoptionNoArg, "True" },
  339.     { "-fs", "fileSystem", XrmoptionSepArg, NULL },
  340.     { "-fn", "font", XrmoptionSepArg, NULL },
  341.     { "-int", "interval", XrmoptionSepArg, NULL },
  342.     { "-bellint", "bellInterval", XrmoptionSepArg, NULL },
  343.     { "-gacol", "redAlert.Color", XrmoptionSepArg, NULL },
  344.     { "-racol", "redAlert.Color", XrmoptionSepArg, NULL },
  345.     { "-yacol", "yellowAlertColor", XrmoptionSepArg, NULL },
  346.     { "-paniclim", "panicAlertLimit", XrmoptionSepArg, NULL },
  347.     { "-ralim", "redAlertLimit", XrmoptionSepArg, NULL },
  348.     { "-yalim", "yellowAlertLimit", XrmoptionSepArg, NULL },
  349.     { "-u", "showDiskUsed", XrmoptionNoArg, "True" },
  350.     { "-v", "verbose", XrmoptionNoArg, "True" },
  351.     { "-width", "usageBarWidth", XrmoptionSepArg, NULL },
  352.     { "-t", "showTitleBar", XrmoptionNoArg, "False" },
  353. };
  354.  
  355.  
  356. #define VERSION      "Mfsm V-1.1 by SDH EngSoft (c) 1995"
  357. #define MAX_LINE     128
  358. #if defined(SGI) || defined(SOLARIS)
  359. #  define DF_COMMAND   "/bin/df -k"
  360. #else
  361. #  define DF_COMMAND   "/bin/df"
  362. #endif
  363.  
  364. String about_text[] = {
  365.     VERSION,
  366.     "All Rights Reserved\n\n",
  367.     "Motif File System Monitor and Alert System\n\n",
  368.     "Arguments to Mfsm:\n\n",
  369.     "-a\t\tshow all mounted file systems.\n",
  370.     "-fs file:file:...\tmonitor given file system.\n",
  371.     "-int sec\t\tusage bar update interval in seconds.\n",
  372.     "-bellint sec\talert bell interval in seconds.\n",
  373.     "-gacol colour\tgreen alert colour.\n",
  374.     "-yacol colour\tyellow alert colour.\n",
  375.     "-racol colour\tred alert colour.\n",
  376.     "-pacol colour\tpanic alert colour.\n",
  377.     "-yalim percent\tyellow alert limit percent.\n",
  378.     "-ralim percent\tred alert limit percent.\n",
  379.     "-palim percent\tpanic alert limit percent.\n",
  380.     "-t\t\tremove title bar.\n",
  381.     "-u\t\tshow disk space used, not free.\n",
  382.     "-v\t\tverbose mode.\n",
  383.     "-width val\t\twidth in pixels of usage bar.\n\n",
  384.     "Keyboard Commands:\n\n",
  385.     "a\tabout Mfsm.\n",
  386.     "f\tdisplay filesystem freespace (default).\n",
  387.     "q\tquit Mfsm.\n",
  388.     "u\tdisplay filesystem usage.\n",
  389.     "v\ttoggle verbose information.\n",
  390.     NULL
  391. };
  392.  
  393. XtAppContext   app;
  394. Widget         toplevel   = NULL;
  395. Widget         popup_menu = NULL;
  396. XtTranslations transTable;
  397. char          *progname   = NULL;
  398. DRIVE_BAR     *drivebar   = NULL;
  399. char           hostname[ MAX_LINE];
  400.  
  401. Widget        BuildMenu( Widget parent, int menu_type, char *menu_title,
  402.              char menu_mnemonic, MenuItem *items);
  403. void          quit_mfsm( Widget w, XButtonEvent *event, String *args,
  404.              int *nargs);
  405. void          activate_popup( Widget w, XtPointer client_data,
  406.                   XButtonPressedEvent *event);
  407. void          about( Widget w, XButtonEvent *event, String *args,
  408.               int *nargs);
  409. void          DestroyShell( Widget widget, Widget *dialog);
  410. void          set_display( Widget w, XButtonEvent *event, String *args,
  411.              int *nargs);
  412. void          init_pixmaps( Widget w);
  413. int           load_icon( Widget w, ICONS *icon);
  414. void          init_colors( Widget w);
  415. void          create_drivebar( Widget w, DRIVE_BAR *dbar);
  416. void          fs_monitor( XtPointer  client_data, XtIntervalId *id);
  417. void          alert_bell( XtPointer  *client_data, XtIntervalId *id);
  418. void          init_usage_bar( DRIVE_BAR *dbar);
  419. void          draw_usage_bar( DRIVE_BAR *dbar);
  420. void          expose_redraw( Widget w, XtPointer client_data,
  421.                 XmDrawnButtonCallbackStruct *cbs);
  422. void          toggle_bell( Widget w, int item,
  423.                XmToggleButtonCallbackStruct *state);
  424. unsigned long get_alert_color( int usage);
  425. DRIVE_BAR    *get_defined_drives( DRIVE_BAR *dbar);
  426. DRIVE_BAR    *get_all_drives( DRIVE_BAR *dbar);
  427. DRIVE_BAR    *add_drivebar( DRIVE_BAR *dbar, char *dev, char *path);
  428. void          get_drive_type( DRIVE_BAR *dbar);
  429. char         *readlink_path( char *path);
  430. void          getfsinfo( DRIVE_BAR *dbar);
  431. #ifdef USE_IOCTL
  432. int           quotactl(int cmd, char *special, uid_t uid, struct dqblk * addr);
  433. #endif
  434. void          check_args( int nargs, char **argv);
  435. void          fatal( char *fmt, ...);
  436. void          warning( char *fmt, ...);
  437. int           fget_line( char *s, int lim, FILE *fp);
  438. int           searchfor( char *string, char *test);
  439.  
  440. Widget tmp_widget;
  441. MenuItem popup_items[] = {
  442.     { "Mfsm Menu", &xmLabelWidgetClass, &tmp_widget,
  443.       '\0', NULL, NULL, True,
  444.       NULL, NULL, NULL},
  445.     { "Separator", &xmSeparatorWidgetClass, &tmp_widget,
  446.       '\0', NULL, NULL, True,
  447.       NULL, NULL, NULL},
  448.     { "About", &xmPushButtonWidgetClass, &tmp_widget,
  449.       'A', "Ctrl<Key>A", "Ctrl A", True,
  450.       about, NULL, NULL},
  451.     { "Quit", &xmPushButtonWidgetClass, &tmp_widget,
  452.       'Q', "Ctrl<Key>C", "Ctrl C", True,
  453.       quit_mfsm, NULL, NULL},
  454.     NULL
  455. };
  456.  
  457. XtActionsRec actionsTable[] = {
  458.     { "about", (XtActionProc) about},
  459.     { "set_display", (XtActionProc) set_display},
  460.     { "quit",  (XtActionProc) quit_mfsm}
  461. };
  462.  
  463. char defaultTranslations[] =
  464.     "<Key>a: about()\n\
  465.      <Key>f: set_display(freespace)\n\
  466.      <Key>q: quit()\n\
  467.      <Key>u: set_display(usage)\n\
  468.      <Key>v: set_display(verbose)";
  469.  
  470.  
  471.  
  472. void main( int nargs, char *argv[])
  473. {
  474.     Widget       form;
  475.     Widget       rowcolumn;
  476.     Widget       label1, label2, label3;
  477.     DRIVE_BAR   *dbar;
  478.     XmString     string;
  479.     char        *h;
  480.     long int     decor;
  481.     Window     iconWindow;
  482.     unsigned int iconW = 40, iconH = 40, tmp;
  483.  
  484.     progname             = *argv;
  485.     Resrcs.show_titlebar = True;
  486.     check_args( nargs, argv);
  487.     decor    = (Resrcs.show_titlebar) ? MWM_DECOR_ALL :
  488.     MWM_DECOR_BORDER | MWM_DECOR_RESIZEH;
  489.     toplevel = XtVaAppInitialize(
  490.     &app, "Mfsm",
  491.         options, XtNumber( options), &nargs, argv, fallbacks,
  492.     XmNmwmDecorations, decor,
  493.     NULL);
  494.     XtAppAddActions( app, actionsTable, XtNumber(actionsTable));
  495.     transTable = XtParseTranslationTable( defaultTranslations);
  496.     XtGetApplicationResources(
  497.     toplevel, &Resrcs,
  498.     resources, XtNumber(resources), NULL, 0);
  499.  
  500.     form = XtVaCreateManagedWidget(
  501.     "form",
  502.         xmFormWidgetClass, toplevel,
  503.     NULL);
  504.     XtOverrideTranslations( form, transTable);
  505.  
  506.     init_pixmaps( form);
  507.     
  508.     /**
  509.       Create icon for program.
  510.       **/
  511. #ifdef HAVE_XPM
  512.     iconWindow = XCreateSimpleWindow(
  513.     XtDisplay( toplevel), RootWindowOfScreen( XtScreen( toplevel)),
  514.     0, 0, /* x, y */
  515.     icon_width, icon_height, 0,
  516.     BlackPixelOfScreen( XtScreen( toplevel)),
  517.     BlackPixelOfScreen( XtScreen( toplevel)));
  518.     XSetWindowBackgroundPixmap( XtDisplay( toplevel), iconWindow,
  519.                 mfsm_icons[ ICONIC].pixmap);
  520.     XtVaSetValues( toplevel, XtNiconWindow, iconWindow, NULL);
  521. #else
  522.     XtVaSetValues ( toplevel,
  523.                     XmNiconPixmap, mfsm_icons[ ICONIC].pixmap,
  524.             NULL);
  525. #endif
  526.  
  527.     /** init_colors( form); **/
  528.  
  529.     rowcolumn = XtVaCreateManagedWidget(
  530.     "drive",
  531.         xmRowColumnWidgetClass, form,
  532.     XmNpacking,             XmPACK_TIGHT,
  533.     XmNorientation,         XmVERTICAL,
  534.     XmNtopAttachment,       XmATTACH_FORM,
  535.     XmNleftAttachment,      XmATTACH_FORM,
  536.     NULL);
  537.     popup_menu = BuildMenu( rowcolumn, XmMENU_POPUP, NULL, '\0',
  538.                 popup_items);
  539.     XtAddEventHandler( rowcolumn, ButtonPressMask, False,
  540.                (XtEventHandler) activate_popup, NULL);
  541.  
  542.     if ( Resrcs.show_all) {
  543.     drivebar = get_all_drives( drivebar);
  544.     }
  545.     drivebar = get_defined_drives( drivebar);
  546.     
  547.     if ( drivebar == NULL)
  548.     fatal( "No filesystems given to monitor.\nTry the commands:\n\tmfsm -a\n\tmfsm -fs $HOME:/tmp\n");
  549.  
  550.     dbar = drivebar;
  551.     while ( dbar != NULL) {
  552.     create_drivebar( rowcolumn, dbar);
  553.     dbar = dbar->next;
  554.     }
  555.     
  556.     h = hostname;
  557.     strcpy( h, "Host: ");
  558.     h = h + strlen( hostname);
  559.     if ( gethostname( h, MAX_LINE) != 0)
  560.     strcpy( h, "Not defined");
  561.     string = XmStringCreateSimple( hostname);
  562.     label1  = XtVaCreateManagedWidget(
  563.     "text",
  564.     xmLabelWidgetClass, form,
  565.     XmNlabelString,     string,
  566.     XmNalignment,       XmALIGNMENT_BEGINNING,
  567.     XmNtopAttachment,   XmATTACH_WIDGET,
  568.     XmNtopWidget,       rowcolumn,
  569.     NULL);
  570.     XmStringFree( string);
  571.     XtAddEventHandler( label1, ButtonPressMask, False,
  572.                (XtEventHandler) activate_popup, NULL);
  573.  
  574.     string = XmStringCreateSimple( VERSION);
  575.     label2  = XtVaCreateManagedWidget(
  576.     "text",
  577.     xmLabelWidgetClass, form,
  578.     XmNlabelString,     string,
  579.     XmNalignment,       XmALIGNMENT_END,
  580.     XmNtopAttachment,   XmATTACH_WIDGET,
  581.     XmNtopWidget,       rowcolumn,
  582.     XmNrightAttachment, XmATTACH_FORM,
  583.     NULL);
  584.     XmStringFree( string);
  585.     XtAddEventHandler( label2, ButtonPressMask, False,
  586.                (XtEventHandler) activate_popup, NULL);
  587.  
  588.     label3  = XtVaCreateManagedWidget(
  589.     "text",
  590.     xmLabelWidgetClass, form,
  591.         XmNlabelType,       XmPIXMAP,
  592.         XmNlabelPixmap,     icon_list[ MOUSE_HELP].pixmap,
  593.     XmNalignment,       XmALIGNMENT_CENTER,
  594.     XmNtopAttachment,   XmATTACH_WIDGET,
  595.     XmNtopWidget,       rowcolumn,
  596.     XmNleftAttachment,  XmATTACH_WIDGET,
  597.     XmNleftWidget,      label1,
  598.     XmNrightAttachment, XmATTACH_WIDGET,
  599.     XmNrightWidget,     label2,
  600.     NULL);
  601.     XtAddEventHandler( label3, ButtonPressMask, False,
  602.                (XtEventHandler) activate_popup, NULL);
  603.  
  604.     XtAppAddTimeOut( app, (unsigned long int) ( Resrcs.interval * 1000.0),
  605.              fs_monitor, (XtPointer) app);
  606.  
  607.     if ( Resrcs.verbose)
  608.     warning( "Going to XWindows loop ...");
  609.  
  610.     XtRealizeWidget(toplevel);
  611.     XtAppMainLoop(app);
  612. }
  613.  
  614.  
  615.  
  616.  
  617. Widget BuildMenu( Widget parent, int menu_type, char *menu_title,
  618.               char menu_mnemonic, MenuItem *items)
  619. {
  620.     Widget menu, cascade = NULL, widget;
  621.     XmString str;
  622.     int i;
  623.  
  624.     if ( menu_type == XmMENU_PULLDOWN) {
  625.     menu = XmCreatePulldownMenu( parent, "_pulldown", NULL, 0);
  626.  
  627.     str = XmStringCreateSimple( menu_title);
  628.     cascade = XtVaCreateManagedWidget(
  629.         menu_title,
  630.         xmCascadeButtonWidgetClass, parent,
  631.         XmNsubMenuId,   menu,
  632.         XmNlabelString, str,
  633.         XmNmnemonic,    menu_mnemonic,
  634.         NULL);
  635.     XmStringFree(str);
  636.     } else
  637.     menu = XmCreatePopupMenu( parent, "_popup", NULL, 0);
  638.     
  639.  
  640.     /* Now add the menu items */
  641.     for (i = 0; items[i].label != NULL; i++) {
  642.         /* If subitems exist, create the pull-right menu by calling this
  643.          * function recursively.  Since the function returns a cascade
  644.          * button, the widget returned is used..
  645.          */
  646.         if (items[i].subitems)
  647.             widget = BuildMenu(
  648.         menu, XmMENU_PULLDOWN,
  649.                 items[i].label, items[i].mnemonic, items[i].subitems);
  650.         else
  651.             widget = XtVaCreateManagedWidget(
  652.         items[i].label, *items[i].class, menu,
  653.                 NULL);
  654.     *(items[i].widget) = widget;
  655.         /* Whether the item is a real item or a cascade button with a
  656.          * menu, it can still have a mnemonic.
  657.          */
  658.         if (items[i].mnemonic)
  659.             XtVaSetValues(widget, XmNmnemonic, items[i].mnemonic, NULL);
  660.         /* any item can have an accelerator, except cascade menus. But,
  661.          * we don't worry about that; we know better in our declarations.
  662.          */
  663.         if (items[i].accelerator) {
  664.             str = XmStringCreateSimple(items[i].accel_text);
  665.             XtVaSetValues(widget,
  666.                 XmNaccelerator, items[i].accelerator,
  667.                 XmNacceleratorText, str,
  668.                 NULL);
  669.             XmStringFree(str);
  670.         }
  671.         /* again, anyone can have a callback -- however, this is an
  672.          * activate-callback.  This may not be appropriate for all items.
  673.          */
  674.         if (items[i].callback)
  675.             XtAddCallback(widget, XmNactivateCallback,
  676.                 items[i].callback, items[i].callback_data);
  677.     XtSetSensitive( widget, items[i].enabled);
  678.     }
  679.     return( menu_type == XmMENU_POPUP ? menu : cascade);
  680. }
  681.  
  682.  
  683.  
  684. void quit_mfsm( Widget w, XButtonEvent *event, String *args, int *nargs)
  685. {
  686.     exit( 0);
  687. }
  688.  
  689.  
  690. void activate_popup( Widget w, XtPointer client_data,
  691.              XButtonPressedEvent *event)
  692. {
  693.     if ( event->button == 3) {
  694.     if ( popup_menu == NULL)
  695.         popup_menu = BuildMenu( w, XmMENU_POPUP, NULL, '\0',
  696.                     popup_items);
  697.     XmMenuPosition( popup_menu, event);
  698.     XtManageChild( popup_menu);
  699.     }
  700. }
  701.  
  702.  
  703. void about( Widget w, XButtonEvent *event, String *args, int *nargs)
  704. {
  705.     static   Widget about_dialog = NULL;
  706.     Widget   pane, text_w, form, button, label;
  707.     Position width, height;
  708.     Arg      arg_list[9];
  709.     int      i;
  710.     char    *p, buf[ BUFSIZ];
  711.  
  712.     
  713.     if ( about_dialog == NULL) {
  714.     about_dialog = XtVaCreatePopupShell(
  715.         "About Mfsm",
  716.         xmDialogShellWidgetClass, toplevel,
  717.         XmNdeleteResponse,        XmDESTROY,
  718.         XmNmwmDecorations,
  719.         MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_RESIZEH,
  720.         XmNminWidth,                 400,
  721.         XmNminHeight,                300,
  722.         NULL);
  723.     
  724.     pane = XtVaCreateWidget(
  725.         "pane", xmPanedWindowWidgetClass, about_dialog,
  726.         XmNsashWidth,  1, /* PanedWindow won't let us set these to 0! */
  727.         XmNsashHeight, 1, /* Make small so user doesn't try to resize */
  728.         NULL);
  729.     
  730.     form = XtVaCreateWidget(
  731.         "form1",
  732.         xmFormWidgetClass, pane,
  733.         NULL);
  734.  
  735.     if ( mfsm_icons[ ABOUT].pixmap == 0)
  736.         load_icon( form, &mfsm_icons[ ABOUT]);
  737.     label = XtVaCreateManagedWidget(
  738.         "pixmap", xmLabelWidgetClass, form,
  739.         XmNlabelType,        XmPIXMAP,
  740.         XmNlabelPixmap,      mfsm_icons[ ABOUT].pixmap,
  741.         XmNtopAttachment,    XmATTACH_FORM,
  742.         XmNleftAttachment,   XmATTACH_FORM,
  743.         XmNrightAttachment,  XmATTACH_FORM,
  744.         NULL);
  745.  
  746.     for ( p = buf, i = 0; about_text[i]; i++) {
  747.         p += strlen( strcpy( p, about_text[i]));
  748.         if (!isspace(p[-1])) /* spaces tabs and newlines are spaces.. */
  749.         *p++ = ' '; /* lines are concatenated together, insert a space */
  750.     }
  751.     *--p = 0; /* get rid of trailing space... */
  752.  
  753.     XtSetArg(arg_list[0], XmNscrollVertical,        True);
  754.     XtSetArg(arg_list[1], XmNscrollHorizontal,      False);
  755.     XtSetArg(arg_list[2], XmNeditMode,              XmMULTI_LINE_EDIT);
  756.     XtSetArg(arg_list[3], XmNeditable,              False);
  757.     XtSetArg(arg_list[4], XmNcursorPositionVisible, False);
  758.     XtSetArg(arg_list[5], XmNwordWrap,              False);
  759.     XtSetArg(arg_list[6], XmNvalue,                 buf);
  760.     XtSetArg(arg_list[7], XmNrows,                  5);
  761.  
  762.     text_w = XmCreateScrolledText(form, "about_text", arg_list, 8);
  763.  
  764.     XtVaSetValues( XtParent(text_w),
  765.                XmNtopAttachment,    XmATTACH_WIDGET,
  766.                XmNtopWidget,        label,
  767.                XmNleftAttachment,   XmATTACH_FORM,
  768.                XmNrightAttachment,  XmATTACH_FORM,
  769.                XmNbottomAttachment, XmATTACH_FORM,
  770.                NULL);
  771.  
  772.     XtManageChild( text_w);
  773.     XtManageChild( form);
  774.  
  775.     form = XtVaCreateWidget(
  776.         "form", xmFormWidgetClass, pane,
  777.         XmNfractionBase,    5,
  778.         NULL);
  779.  
  780.     button = XtVaCreateManagedWidget(
  781.         "Ok",
  782.         xmPushButtonWidgetClass, form,
  783.         XmNtopAttachment,        XmATTACH_FORM,
  784.         XmNbottomAttachment,     XmATTACH_FORM,
  785.         XmNleftAttachment,       XmATTACH_POSITION,
  786.         XmNleftPosition,         2,
  787.         XmNrightAttachment,      XmATTACH_POSITION,
  788.         XmNrightPosition,        3,
  789.         XmNshowAsDefault,        True,
  790.         XmNdefaultButtonShadowThickness, 1,
  791.         NULL);
  792.     XtAddCallback( button, XmNactivateCallback,
  793.                (XtCallbackProc) DestroyShell, &about_dialog);
  794.  
  795.     XtManageChild( form);
  796.     {
  797.         Dimension h;
  798.         XtVaGetValues( button, XmNheight, &h, NULL);
  799.         XtVaSetValues(form, XmNpaneMaximum, h, XmNpaneMinimum, h, NULL);
  800.     }
  801.     XtManageChild( pane);
  802.     /**
  803.       Position about window in middle upper third of screen.
  804.       **/
  805.     XtVaGetValues( about_dialog,
  806.                XmNheight, &height,
  807.                XmNwidth,  &width,
  808.                NULL);
  809.     XtVaSetValues(
  810.         about_dialog,
  811.         XmNx, ( WidthOfScreen( XtScreen( toplevel)) - width) / 2,
  812.         XmNy, ( HeightOfScreen( XtScreen( toplevel)) - height) / 3,
  813.         NULL);
  814.     XtPopup( about_dialog, XtGrabNone);
  815.     }
  816. }
  817.  
  818.  
  819.  
  820. void DestroyShell( Widget w, Widget *dialog)
  821. {
  822.     XtDestroyWidget( *dialog);
  823.     if ( mfsm_icons[ ABOUT].pixmap != 0) {
  824.     XFreePixmap( XtDisplay( *dialog), mfsm_icons[ ABOUT].pixmap);
  825.     mfsm_icons[ ABOUT].pixmap = 0;
  826.     }
  827.     *dialog = (Widget) NULL;
  828. }
  829.  
  830.  
  831.  
  832.  
  833. void set_display( Widget w, XButtonEvent *event, String *args, int *nargs)
  834. {
  835.     int nitems = *nargs;
  836.  
  837.     if ( Resrcs.verbose)
  838.     warning( "set_display: NArgs = %d Arg = \"%s\"\n", nitems, *args);
  839.     while ( nitems) {
  840.     if ( strcmp( *args, "freespace") == 0)
  841.         Resrcs.show_diskused = False;
  842.     else if ( strcmp( *args, "usage") == 0)
  843.         Resrcs.show_diskused = True;
  844.     else if ( strcmp( *args, "verbose") == 0)
  845.         Resrcs.verbose = !Resrcs.verbose;
  846.     if ( --nitems != 0)
  847.         ++args;
  848.     }
  849. }
  850.  
  851.  
  852.  
  853.  
  854. void init_pixmaps( Widget w)
  855. {
  856.     ICONS *icon;
  857.     icon = icon_list;
  858.     while( icon->bm_bits != NULL) {
  859.     load_icon( w, icon);
  860.     ++icon;
  861.     }
  862.     load_icon( w, &mfsm_icons[ ICONIC]);
  863. }
  864.  
  865.  
  866.  
  867. int load_icon( Widget w, ICONS *icon)
  868. {
  869.     Pixel   fg, bg;
  870.     Screen *scr;
  871. #ifdef HAVE_XPM
  872.     XpmAttributes  pixmapAttrs;
  873.     Pixmap         pixmapShapeMask = (Pixmap) NULL;
  874.     XpmColorSymbol pixmapColorSymbols[ 1];
  875.     int            xpm_error;
  876. #endif    
  877.     scr = XtScreen( w);
  878.     XtVaGetValues( w,
  879.            XmNforeground, &fg,
  880.            XmNbackground, &bg,
  881.            NULL);
  882.     if ( Resrcs.verbose)
  883.     warning( "pixmap fg = %d bg = %d\n", fg, bg);
  884.  
  885. #ifdef HAVE_XPM
  886.     pixmapColorSymbols[0].name  = NULL;
  887.     pixmapColorSymbols[0].value = "none";
  888.     pixmapColorSymbols[0].pixel = bg;
  889.     pixmapColorSymbols[0].name  = NULL;
  890.     pixmapAttrs.colorsymbols    = pixmapColorSymbols;
  891.     pixmapAttrs.numsymbols      = 1;
  892.     pixmapAttrs.closeness       = 20000;
  893.     pixmapAttrs.valuemask       = 
  894.     XpmColorSymbols | XpmCloseness;
  895.     if ( icon->xpm_data == NULL || ( xpm_error = XpmCreatePixmapFromData(
  896.     XtDisplay( w),
  897.     RootWindowOfScreen( scr),
  898.     icon->xpm_data, &icon->pixmap, &pixmapShapeMask,
  899.     &pixmapAttrs))  != XpmSuccess) {
  900.     if ( !icon->mask) {
  901.         fg = BlackPixelOfScreen( scr);
  902.         bg = WhitePixelOfScreen( scr);
  903.     }
  904.     icon->pixmap = XCreatePixmapFromBitmapData(
  905.         XtDisplay( w),
  906.         RootWindowOfScreen( scr),
  907.         icon->bm_bits, icon->bm_width, icon->bm_height,
  908.         1, 0, /**fg, bg,**/
  909.         DefaultDepthOfScreen( scr));
  910.     if ( Resrcs.verbose)
  911.         warning( "XPM error - %d", xpm_error);
  912.     } else
  913.     if ( icon->xpm_data != NULL && pixmapShapeMask != 0)
  914.         XFreePixmap( XtDisplay( w), pixmapShapeMask);
  915. #else
  916.     if ( !icon->mask) {
  917.     fg = BlackPixelOfScreen( scr);
  918.     bg = WhitePixelOfScreen( scr);
  919.     }        
  920.     icon->pixmap = XCreatePixmapFromBitmapData(
  921.     XtDisplay( w),
  922.     RootWindowOfScreen( scr),
  923.     icon->bm_bits, icon->bm_width, icon->bm_height,
  924.     fg, bg,
  925.     DefaultDepthOfScreen( scr));
  926. #endif
  927.     return( icon->pixmap != 0 ? True : False);
  928. }
  929.  
  930.  
  931.  
  932. /**
  933. void init_colors( Widget w)
  934. {
  935.     Display *dpy  = XtDisplay( w);
  936.     Colormap cmap = DefaultColormapOfScreen( XtScreen( w));
  937.     XColor   unused;
  938.     int      i;
  939.  
  940.     for ( i = 0; i < MAX_ALERT_COLORS; ++i) {
  941.       if ( !XAllocNamedColor( dpy, cmap, bar_color[ i], &alert_color[ i], &unused)) {
  942.       char buf[ 32];
  943.       
  944.       sprintf( "Can't allocate color %s", bar_color[ i]);
  945.       XtWarning( buf);
  946.       exit( 1);
  947.       }
  948.     }
  949. }
  950. **/
  951.  
  952. void create_drivebar( Widget w, DRIVE_BAR *dbar)
  953. {
  954.     Widget    rowcolumn1, frame1;
  955.     Widget    label1;
  956.     Widget    drawing1;
  957.     Widget    toggle1;
  958.  
  959.     rowcolumn1 = XtVaCreateManagedWidget(
  960.     "rowcolumn",
  961.         xmRowColumnWidgetClass, w,
  962.     XmNpacking,             XmPACK_TIGHT,
  963.     XmNorientation,         XmHORIZONTAL,
  964.     XmNmarginHeight,        0,
  965.     XmNmarginWidth,         0,
  966.     XmNleftAttachment,      XmATTACH_FORM,
  967.     XmNrightAttachment,     XmATTACH_FORM,
  968.     NULL);
  969.  
  970.     label1 = XtVaCreateManagedWidget(
  971.     "pixmap",
  972.         xmLabelWidgetClass, rowcolumn1,
  973.         XmNlabelType,       XmPIXMAP,
  974.         XmNlabelPixmap,     icon_list[ dbar->type].pixmap,
  975.         NULL);
  976.     XtOverrideTranslations( label1, transTable);
  977.  
  978.     frame1 = XtVaCreateManagedWidget(
  979.     "frame",
  980.     xmFrameWidgetClass,  rowcolumn1,
  981.     XmNshadowType,       XmSHADOW_IN,
  982.     XmNmarginWidth,      0,
  983.     XmNmarginHeight,     0,
  984.     NULL);
  985.  
  986.     drawing1 = XtVaCreateManagedWidget(
  987.     "usageBar",
  988.     xmDrawingAreaWidgetClass, frame1,
  989.     /** XmNresizePolicy,          XmRESIZE_NONE, **/
  990.     XmNwidth,                 Resrcs.width,
  991.     NULL);
  992.     XtOverrideTranslations( drawing1, transTable);
  993.     XtAddCallback( drawing1, XmNexposeCallback,
  994.            (XtCallbackProc) expose_redraw, NULL);
  995.  
  996.     toggle1 = XtVaCreateManagedWidget(
  997.     "toggle",
  998.     xmToggleButtonWidgetClass, rowcolumn1,
  999.     XmNlabelType,              XmPIXMAP,
  1000.     XmNlabelPixmap,            icon_list[ NOBELL].pixmap,
  1001.     XmNselectPixmap,           icon_list[ BELL].pixmap,
  1002.     XmNhighlightThickness,     0,
  1003.     NULL);
  1004.     XmToggleButtonSetState( toggle1, dbar->bell, False);
  1005.     XtOverrideTranslations( toggle1, transTable);
  1006.     XtAddCallback( toggle1, XmNvalueChangedCallback,
  1007.           (XtCallbackProc) toggle_bell, NULL); 
  1008.     
  1009.     dbar->widget      = rowcolumn1;
  1010.     dbar->usagebar    = drawing1;
  1011.     dbar->gc          = XCreateGC( XtDisplay( drawing1),
  1012.                 RootWindowOfScreen( XtScreen( drawing1)),
  1013.                    0, NULL);
  1014.     dbar->bell_toggle = toggle1;
  1015. }
  1016.  
  1017.  
  1018.  
  1019. void fs_monitor( XtPointer  client_data, XtIntervalId *id)
  1020. {
  1021.     DRIVE_BAR   *dbar;
  1022.     
  1023.     if ( Resrcs.verbose)
  1024.     warning( "fs_monitor ...");
  1025.     
  1026.     dbar = drivebar;
  1027.     while ( dbar != NULL) {
  1028.     if ( dbar->pixmap != 0)
  1029.         getfsinfo( dbar);
  1030.         draw_usage_bar( dbar);
  1031.     dbar = dbar->next;
  1032.     }
  1033.  
  1034.     XtAppAddTimeOut( (XtAppContext) client_data,
  1035.              (unsigned long int) ( Resrcs.interval * 1000.0),
  1036.              fs_monitor, client_data);
  1037. }
  1038.  
  1039.  
  1040.  
  1041. void alert_bell( XtPointer  *client_data, XtIntervalId *id)
  1042. {
  1043.     DRIVE_BAR *dbar = (DRIVE_BAR *) client_data;
  1044.  
  1045.     if ( dbar->bell && dbar->bell_activated) {
  1046.     XBell( XtDisplay( dbar->widget), 50);
  1047.     XtAppAddTimeOut( app,
  1048.              (unsigned long int)( Resrcs.bell_interval * 1000.0),
  1049.              (XtTimerCallbackProc) alert_bell, (XtPointer) dbar);
  1050.     } else {
  1051.     XtRemoveTimeOut( *id);
  1052.     dbar->bell_activated = False;
  1053.     }
  1054. }
  1055.  
  1056.  
  1057.  
  1058. void init_usage_bar( DRIVE_BAR *dbar)
  1059. {
  1060.     Display   *dpy;
  1061.     Screen    *scr;
  1062.     Pixel      bg;
  1063.     int        i, x;
  1064.  
  1065.     dpy = XtDisplay( dbar->usagebar);
  1066.     scr = XtScreen( dbar->usagebar);
  1067.     XtVaGetValues( dbar->usagebar,
  1068.            XmNwidth,      &(dbar->width),
  1069.            XmNheight,     &(dbar->height),
  1070.            XmNbackground, &bg,
  1071.            NULL);
  1072.     if ( dbar->pixmap == 0 && dbar->width != 0 && dbar->height != 0) {
  1073.     dbar->pixmap = XCreatePixmap(
  1074.         dpy,
  1075.         RootWindowOfScreen( scr),
  1076.         dbar->width, dbar->height,
  1077.         DefaultDepthOfScreen( scr));
  1078.     }
  1079.     XSetForeground( dpy, dbar->gc, bg);
  1080.     XFillRectangle( dpy, dbar->pixmap, dbar->gc,
  1081.             0, 0, dbar->width, dbar->height);
  1082.     /**
  1083.       Draw Tic marks
  1084.       **/
  1085.     XSetForeground( dpy, dbar->gc, BlackPixelOfScreen( scr));
  1086.     for ( i = 2; i < 10; i += 2) {
  1087.     x = dbar->width * i / 10;
  1088.     XFillRectangle( dpy, dbar->pixmap, dbar->gc, x, 0, 2, 3);
  1089.     XFillRectangle( dpy, dbar->pixmap, dbar->gc, x, dbar->height - 3,
  1090.             2, 3);
  1091.     }
  1092.     XSetFont( dpy, dbar->gc, Resrcs.font->fid);
  1093. }
  1094.  
  1095.  
  1096. void draw_usage_bar( DRIVE_BAR *dbar)
  1097. {
  1098.     Display     *dpy;
  1099.     Window       win;
  1100.     Screen      *scr;
  1101.     Pixel        bg;
  1102.     char         buf[ 16];
  1103.     int          x, y, font_dim;
  1104.     int          bar_x1, bar_y1, bar_x2, bar_y2;
  1105.     int          text_margin = 3;
  1106.     XPoint       points[ 4];
  1107.  
  1108.     dpy    = XtDisplay( dbar->usagebar);
  1109.     win    = XtWindow( dbar->usagebar);
  1110.     scr    = XtScreen( dbar->usagebar);
  1111.     bar_x1 = 0;
  1112.     bar_y1 = 3;
  1113.     bar_x2 = dbar->width * dbar->usage / 100;
  1114.     bar_y2 = dbar->height - 6;
  1115.     /**
  1116.       Secondary test to make sure tha a pixmap has been allocated.
  1117.       **/
  1118.     if ( dbar->pixmap == 0)
  1119.     return;
  1120.     /**
  1121.       Draw usage bar
  1122.       **/
  1123.     XtVaGetValues( dbar->usagebar, XmNbackground, &bg, NULL);
  1124.     XSetForeground( dpy, dbar->gc, bg);
  1125.     XFillRectangle( dpy, dbar->pixmap, dbar->gc,
  1126.             bar_x1, bar_y1, dbar->width, bar_y2);
  1127.     if ( dbar->usage < Resrcs.panic_alert) {
  1128.     XSetForeground( dpy, dbar->gc, get_alert_color( dbar->usage));
  1129.     XFillRectangle( dpy, dbar->pixmap, dbar->gc,
  1130.             bar_x1, bar_y1, bar_x2, bar_y2);
  1131.     dbar->bell_activated = False;
  1132.     } else {
  1133.     XSetForeground( dpy, dbar->gc, BlackPixelOfScreen( scr));
  1134.     XFillRectangle( dpy, dbar->pixmap, dbar->gc,
  1135.             bar_x1, bar_y1, bar_x2, bar_y2);
  1136.     XSetForeground( dpy, dbar->gc, Resrcs.pa_color);
  1137.     for ( x = dbar->height; x <= bar_x2; x += 2 * dbar->height) {
  1138.         points[ 0].x = x;
  1139.         points[ 0].y = bar_y1;
  1140.         points[ 1].x = x + dbar->height;
  1141.         points[ 1].y = bar_y1;
  1142.         points[ 2].x = x;
  1143.         points[ 2].y = bar_y2 + 3;
  1144.         points[ 3].x = x - dbar->height;
  1145.         points[ 3].y = bar_y2 + 3;
  1146.         XFillPolygon( dpy, dbar->pixmap, dbar->gc, points, 4,
  1147.               Convex, CoordModeOrigin);
  1148.     }
  1149.     if ( dbar->bell && !dbar->bell_activated) {
  1150.         dbar->bell_activated = True;
  1151.         XBell( dpy, 50);
  1152.         XtAppAddTimeOut(
  1153.         app, (unsigned long int)( Resrcs.bell_interval * 1000.0),
  1154.         (XtTimerCallbackProc) alert_bell, (XtPointer) dbar);
  1155.     }
  1156.     }
  1157.     XSetForeground( dpy, dbar->gc, WhitePixelOfScreen( scr));
  1158.     XDrawLine( dpy, dbar->pixmap, dbar->gc, bar_x1, bar_y1, bar_x2, bar_y1);
  1159.     XSetForeground( dpy, dbar->gc, BlackPixelOfScreen( scr));
  1160.     XDrawLine( dpy, dbar->pixmap, dbar->gc,
  1161.            bar_x1, bar_y2 + 2, bar_x2, bar_y2 + 2);
  1162.     XDrawLine( dpy, dbar->pixmap, dbar->gc,
  1163.            bar_x2, bar_y1, bar_x2, bar_y2 + 2);
  1164.     /**
  1165.       Draw Text
  1166.       **/
  1167.     /** font_info = XQueryFont( dpy, XGContextFromGC( dbar->gc)); **/
  1168.     font_dim  = Resrcs.font->ascent + Resrcs.font->descent;
  1169.     y         = ( dbar->height - font_dim) / 2 + Resrcs.font->ascent;
  1170.     XDrawString( dpy, dbar->pixmap, dbar->gc, text_margin, y,
  1171.          dbar->name, strlen( dbar->name));
  1172.     if ( dbar->usage_type == QUOTA_SPACE)
  1173.     sprintf( buf, "%3.2fMb (Q)", dbar->mbytes);
  1174.     else
  1175.     sprintf( buf, "%3.2fMb", dbar->mbytes);
  1176.     font_dim = XTextWidth( Resrcs.font, buf, strlen( buf));
  1177.     XDrawString( dpy, dbar->pixmap, dbar->gc,
  1178.          dbar->width - font_dim - text_margin, y,
  1179.          buf, strlen( buf));
  1180.     /**
  1181.       Swap pixmap to screen.
  1182.       **/
  1183.     XCopyArea( dpy, dbar->pixmap, win, dbar->gc, 0, 0,
  1184.            dbar->width, dbar->height, 0, 0);
  1185. }
  1186.  
  1187.  
  1188. void expose_redraw( Widget w, XtPointer client_data,
  1189.           XmDrawnButtonCallbackStruct *cbs)
  1190. {
  1191.     DRIVE_BAR *dbar;
  1192.     Pixel      bg;
  1193.  
  1194.     dbar = drivebar;
  1195.     while ( dbar != NULL && dbar->usagebar != w)
  1196.     dbar = dbar->next;
  1197.     if ( dbar == NULL) {
  1198.     warning( "expose_redraw: Widget not found\n");
  1199.     return;
  1200.     }
  1201.  
  1202.     if (cbs->reason == XmCR_EXPOSE) {
  1203.     init_usage_bar( dbar);
  1204.     draw_usage_bar( dbar);
  1205.  
  1206.     } else { /* XmCR_RESIZE */
  1207.     XtVaGetValues( dbar->usagebar,
  1208.                XmNwidth,      &(dbar->width),
  1209.                XmNheight,     &(dbar->height),
  1210.                XmNbackground, &bg,
  1211.                NULL);
  1212.         puts("Usage Bar Resize");
  1213.     }
  1214. }
  1215.  
  1216.  
  1217. void toggle_bell( Widget w, int item,
  1218.           XmToggleButtonCallbackStruct *state)
  1219. {
  1220.     DRIVE_BAR *dbar;
  1221.  
  1222.     dbar = drivebar;
  1223.     while ( dbar != NULL && dbar->bell_toggle != w)
  1224.     dbar = dbar->next;
  1225.     if ( dbar == NULL) {
  1226.     warning( "toggle_bell: Widget not found\n");
  1227.     return;
  1228.     }
  1229.  
  1230.     dbar->bell = state->set;
  1231. }
  1232.  
  1233.  
  1234. unsigned long get_alert_color( int usage)
  1235. {
  1236.     if ( usage < Resrcs.yellow_alert )
  1237.     return( Resrcs.ga_color);
  1238.     else if ( usage < Resrcs.red_alert)
  1239.     return( Resrcs.ya_color);
  1240.     else
  1241.     return( Resrcs.ra_color);
  1242. }
  1243.  
  1244.  
  1245.  
  1246. DRIVE_BAR *get_defined_drives( DRIVE_BAR *dbar)
  1247. {
  1248.     char  tmp[ 2 * MAX_LINE];
  1249.     FILE *ifp;
  1250.     char *s, *fs;
  1251.     char  tmp_file[] = "/tmp/mfsm-XXXXXX";
  1252.     char *dev;
  1253.  
  1254.     mktemp( tmp_file);
  1255.     fs = Resrcs.filesystem;
  1256.     while ( fs != NULL && strlen( fs) != 0) {
  1257.     if (( s = strchr( fs, ':')) != NULL) {
  1258.         *s = '\0';
  1259.         ++s;
  1260.     }
  1261.     sprintf( tmp, "%s %s >%s", DF_COMMAND, fs, tmp_file);
  1262.     if ( system( tmp) != 0)
  1263.         fatal( "Can't run df command for file system %s", fs);
  1264.     if (( ifp = fopen( tmp_file, "r")) == NULL)
  1265.         fatal( "Can't read temp file for df command");
  1266. #ifndef SCO
  1267.     fget_line( tmp, MAX_LINE, ifp);
  1268. #endif
  1269.     while ( fget_line( tmp, MAX_LINE, ifp) != EOF) {
  1270.         /**
  1271.           BSD df returns the format:
  1272.           device other_info mount_point
  1273.           
  1274.           SVR4 df returns the format:
  1275.           mount_point (device) other_info
  1276.           **/
  1277.         /**
  1278.           Search for device.
  1279.           **/
  1280. #ifdef USE_SVR4DF  /** SRVR4 df(1) **/
  1281.         if (( dev = strchr( tmp, '(')) == NULL) {
  1282.         warning( "The df(1) command is not a SVR4 version.");
  1283.         fatal( "Try compiling without -DUSE_SRV4DF.");
  1284.         }
  1285.         strcpy( tmp, dev + 1);
  1286. #endif
  1287.         dev = tmp;
  1288.         while( !isspace( *dev) && *dev != ')')
  1289.         ++dev;
  1290.         *dev = '\0';
  1291.         dbar = add_drivebar( dbar, tmp, fs);
  1292.     }
  1293.     fclose( ifp);
  1294.     unlink( tmp_file);
  1295.     fs = s;
  1296.     }
  1297.     return( dbar);
  1298. }
  1299.  
  1300.  
  1301.  
  1302. DRIVE_BAR *get_all_drives( DRIVE_BAR *dbar)
  1303. {
  1304.     char  tmp[ 2 * MAX_LINE];
  1305.     FILE *ifp;
  1306.     char  tmp_file[] = "/tmp/mfsm-XXXXXX";
  1307.     char *path, *dev;
  1308.     
  1309.     mktemp( tmp_file);
  1310.     sprintf( tmp, "%s >%s", DF_COMMAND, tmp_file);
  1311.     if ( system( tmp) != 0)
  1312.     fatal( "Can't run df command");
  1313.     if (( ifp = fopen( tmp_file, "r")) == NULL)
  1314.     fatal( "Can't read temp file for df command");
  1315. #ifndef SCO
  1316.     fget_line( tmp, MAX_LINE, ifp);
  1317. #endif
  1318.     while ( fget_line( tmp, MAX_LINE, ifp) != EOF) {
  1319.     /**
  1320.       BSD df returns the format:
  1321.         device other_info mount_point
  1322.  
  1323.       SVR4 df returns the format:
  1324.         mount_point (device) other_info
  1325.       **/
  1326.     /**
  1327.       Search for path.
  1328.       **/
  1329. #ifdef USE_SVR4DF /** SVR4 df(1) **/
  1330.     path = tmp;
  1331.     while( !isspace( *path) && *path != '(')
  1332.         ++path;
  1333.     if (( dev = strchr( path, '(')) == NULL) {
  1334.         warning( "The df(1) command is not a SVR4 version.");
  1335.         fatal( "Try compiling without -DUSE_SRV4DF.");
  1336.     }
  1337.     *path = '\0';
  1338.     path  = tmp;
  1339.     ++dev;
  1340.     while( !isspace( *dev) && *dev != ')')
  1341.         ++dev;
  1342.     *dev = '\0';
  1343. #else /** BSD df(1) **/
  1344.     path = tmp + strlen( tmp) - 1; /** Save the end pointer **/
  1345.      /**
  1346.        Check if line is split, and read another if needed
  1347.        **/
  1348.      if (( dev = strchr( tmp, '%')) == NULL) {
  1349.         fget_line( path, MAX_LINE, ifp);
  1350.         path = tmp + strlen( tmp) - 1; /** Save new end pointer **/
  1351.     }
  1352.     /**
  1353.       Eat spaces at end of line.
  1354.       **/
  1355.     while( isspace( *path))
  1356.         *(path--) = '\0';
  1357.     /**
  1358.       Then take the pathname.
  1359.       **/
  1360.     while( !isspace( *path))
  1361.         --path;
  1362.     ++path;
  1363.     /**
  1364.       Search for device.
  1365.       **/
  1366.     dev = tmp;
  1367.     while( !isspace( *dev))
  1368.         ++dev;
  1369.     *dev = '\0';
  1370.     dev  = tmp;
  1371. #endif
  1372. #ifdef SOLARIS
  1373.     if ( !strcmp( dev, "/proc") || !strcmp( dev, "fd"))
  1374.         continue;
  1375. #endif
  1376.     dbar = add_drivebar( dbar, dev, path);
  1377.     }
  1378.     fclose( ifp);
  1379.     unlink( tmp_file);
  1380.     return( dbar);
  1381. }
  1382.  
  1383.  
  1384.  
  1385. DRIVE_BAR *add_drivebar( DRIVE_BAR *dbar, char *dev, char *path)
  1386. {
  1387.     if ( dbar == NULL) {
  1388.     if (( dbar = (DRIVE_BAR *) malloc( sizeof( DRIVE_BAR))) == NULL)
  1389.         fatal( "Can't allocate memory for drive \"%s\"\n", path);
  1390.     dbar->name     = strdup( path);
  1391.     dbar->dev      = strdup( dev);
  1392.     dbar->path     = readlink_path( path);
  1393.  
  1394.     /** 
  1395.       Make sure that the path is not a link.
  1396.       **/
  1397.     if ( Resrcs.verbose)
  1398.         warning( "Link for path \'%s\" is \"%s\"\n",
  1399.              dbar->name, dbar->path);
  1400.     dbar->userid      = 0;
  1401.     dbar->type        = 0;
  1402.     get_drive_type( dbar);
  1403.     dbar->widget      = NULL;
  1404.     dbar->usagebar    = NULL;
  1405.     dbar->gc          = NULL;
  1406.     dbar->pixmap      = 0;
  1407.     dbar->width       = 0;
  1408.     dbar->height      = 0;
  1409.     dbar->mbytes      = 0.0;
  1410.     dbar->usage       = 0;
  1411.     dbar->bell_toggle = NULL;
  1412.     dbar->bell        = True;
  1413.     dbar->bell_activated = False;
  1414.     dbar->next        = NULL;
  1415.     } else
  1416.     dbar->next = add_drivebar( dbar->next, dev, path);
  1417.     return( dbar);
  1418. }
  1419.  
  1420.  
  1421.  
  1422. void get_drive_type( DRIVE_BAR *dbar)
  1423. {
  1424.     char  tmp[ MAX_LINE];
  1425.     char *s;
  1426.  
  1427.     /**
  1428.       Check passwd file to see if *dbar->path belong to a user account.
  1429.       **/
  1430.     if ( strcmp( dbar->path, "/") != 0) {
  1431.     struct passwd *pw_field;
  1432.  
  1433.     setpwent();
  1434.     while(( pw_field = getpwent()) != NULL) {
  1435.         if ( strcmp( pw_field->pw_dir, dbar->name) == 0) {
  1436.         dbar->userid = pw_field->pw_uid;
  1437.         dbar->type   = USER;
  1438.         return;
  1439.         }
  1440.     }
  1441.     }
  1442.  
  1443.     strcpy( tmp, dbar->dev);
  1444.     s = tmp;
  1445.     while ( *s)
  1446.     *s++ = tolower( *s);
  1447.     if ( strchr( tmp, ':') != NULL || strchr( tmp, '@') != NULL)
  1448.     dbar->type = NETWORK_DISK;
  1449.     else if ( searchfor( tmp, "cdrom"))
  1450.     dbar->type = CDROM;
  1451.     else if ( searchfor( tmp, "floppy"))
  1452.     dbar->type = FLOPPY_DISK;
  1453.     else
  1454.     dbar->type = HARD_DISK;
  1455. }
  1456.  
  1457.  
  1458. char *readlink_path( char *path)
  1459. {
  1460.  
  1461.     char  tmp[ MAX_LINE];
  1462.     char  tmp2[ MAX_LINE];
  1463.     char  newpath[ MAX_LINE];
  1464.     char *s1, *s2, *s3;
  1465.     int   lstring;
  1466.  
  1467.  
  1468.     strcpy( tmp, path);
  1469.     if ( *tmp != '/')
  1470.     if ( getcwd( tmp2, MAX_LINE) != NULL) {
  1471.         sprintf( newpath, "%s/%s", tmp2, tmp);
  1472.         strcpy( tmp, newpath);
  1473.     }
  1474.     strcpy( newpath, "/");
  1475.     s1 = tmp;
  1476.     while (( s2 = strchr( s1 + 1, '/')) != NULL) {
  1477.     *s2 = '\0';
  1478.     sprintf( tmp2, "%s%s", newpath, s1);
  1479.     if (( lstring = readlink( s1, tmp2, MAX_LINE)) > 0) {
  1480.         *( tmp2 + lstring) = '\0';
  1481.         if ( *tmp2 == '.') {
  1482.         s3         = strrchr( newpath, '/');
  1483.         *( s3 + 1) = '\0';
  1484.         sprintf( tmp, "%s%s/", newpath, tmp2);
  1485.         } else {
  1486.         sprintf( newpath, "%s/", tmp2);
  1487.         }
  1488.     } else {
  1489.         sprintf( newpath, "%s%s/", newpath, s1 + 1);
  1490.     }
  1491.     s1 = s2;
  1492.     }
  1493.     sprintf( newpath, "%s%s", newpath, s1 + 1);
  1494.     if (( lstring = readlink( newpath, tmp2, MAX_LINE)) > 0) {
  1495.     *( tmp2 + lstring) = '\0';
  1496.     if ( *tmp2 == '.') {
  1497.         s3         = strrchr( newpath, '/');
  1498.         *( s3 + 1) = '\0';
  1499.         sprintf( tmp, "%s%s", newpath, tmp2);
  1500.         path = strdup( tmp);
  1501.     } else {
  1502.         path = strdup( tmp2);
  1503.     }
  1504.     } else if ( strcmp( newpath, path) != 0)
  1505.     path = strdup( newpath);
  1506.     else
  1507.     path = strdup( path);
  1508.     if ( *path != '/') {
  1509.     sprintf( tmp, "/%s", path);
  1510.     free( path);
  1511.     path = strdup( tmp);
  1512.     }
  1513.     return( path);
  1514. }
  1515.  
  1516. void getfsinfo( DRIVE_BAR *dbar)
  1517. {
  1518.  
  1519. #ifdef SOLARIS
  1520.     struct statvfs sb;
  1521. #else
  1522.     struct statfs  sb;
  1523. #endif
  1524.     unsigned long  bfree, bsize;
  1525.  
  1526. #if defined(DIGITAL_UNIX)
  1527.     statfs( dbar->path, &sb);
  1528.     bfree = sb.f_bavail;
  1529.     bsize = sb.f_fsize;
  1530. #elif defined(SGI) || defined(SCO)
  1531.     statfs( dbar->path, &sb, sizeof(struct statfs), 0);
  1532.     bfree = sb.f_bfree;
  1533.     bsize = sb.f_bsize;
  1534. #if defined(SCO)
  1535.     /* Dunno why this is necesary but it is otherwise stats are wrong by a
  1536.      * factor of 2 (bsize = 1024 ) - suspect one of the blocksize or
  1537.      *  block numbers returned are bogus...
  1538.      * Note I've limited this to HTFS but may also be necessary for 
  1539.      * other FS as well
  1540.      * Hops 22-Jun-95
  1541.      */
  1542.     if (sb.f_fstyp == 5 )   /* HTFS */
  1543.     {
  1544.         if ( bsize > 512 ) bsize = 512 ;
  1545.     }
  1546. #endif
  1547. #elif defined (SOLARIS)
  1548.     statvfs( dbar->path, &sb);
  1549.     bfree = sb.f_bavail;
  1550.     bsize = sb.f_frsize;
  1551. #else
  1552.     statfs( dbar->path, &sb);
  1553.     bfree = sb.f_bavail;
  1554.     bsize = sb.f_bsize;
  1555. #endif
  1556.  
  1557. #ifdef HAVE_QUOTAS
  1558.     if ( dbar->type == USER) {
  1559.     struct dqblk qd;
  1560.  
  1561. #if defined(AIX)
  1562.     if ( quotactl( dbar->path, Q_GETQUOTA, dbar->userid, (char *) &qd) == 0) {
  1563. #elif defined(SGI) || defined(SUNOS)
  1564.     if ( quotactl( Q_GETQUOTA, dbar->dev, dbar->userid, (char *) &qd) == 0) {
  1565. #elif defined(SOLARIS)
  1566.     if ( quotactl( Q_GETQUOTA, dbar->path, dbar->userid, &qd) == 0) {
  1567. #else
  1568.     if ( quotactl( Q_GETQUOTA, dbar->dev, dbar->userid, (char *) &qd) == 0) {
  1569. #endif
  1570.         if ( qd.dqb_bhardlimit != 0 &&
  1571.          ( qd.dqb_bhardlimit - qd.dqb_curblocks) < bfree) {
  1572.         if ( Resrcs.show_diskused)
  1573.             dbar->mbytes =
  1574.             (float)(qd.dqb_curblocks) *
  1575.             (float)(bsize) / 1048576.0;
  1576.         else
  1577.             dbar->mbytes =
  1578.             (float)(qd.dqb_bhardlimit - qd.dqb_curblocks) *
  1579.             (float)(bsize) / 1048576.0;
  1580.         dbar->usage = 100 * qd.dqb_curblocks /
  1581.             qd.dqb_bhardlimit;
  1582.         dbar->usage_type = QUOTA_SPACE;
  1583.         return;
  1584.         }
  1585.     } else if ( Resrcs.verbose)
  1586.         fprintf( stderr, "Error %d on quotas for device \"%s\" at \"%s\"\n",
  1587.              errno, dbar->dev, dbar->path);
  1588.     }
  1589. #endif /** HAVE_QUOTAS **/
  1590.     if ( Resrcs.show_diskused)
  1591.     dbar->mbytes     = (float)(sb.f_blocks - bfree) *
  1592.         (float)(bsize) / 1048576.0;
  1593.     else
  1594.     dbar->mbytes     = (float)(bfree) * (float)(bsize) / 1048576.0;
  1595.     dbar->usage      = 
  1596.     (sb.f_blocks > 0) ? 100 * (sb.f_blocks - bfree) / sb.f_blocks : 0;
  1597.     dbar->usage_type = SYSTEM_SPACE;
  1598. }
  1599.  
  1600.  
  1601. #ifdef USE_IOCTL
  1602.  
  1603. /*
  1604.  * Thanks to Davin Milun for Solaris 2.x support. Email: milun@cs.buffalo.edu.
  1605.  * He explaines the following:
  1606.  * 
  1607.  * Define the "quotactl" function as in Solaris 1, based on ioctl().
  1608.  * By Marc Mazuhelli <mazu@dmi.usherb.ca>
  1609.  * The "special" parameter is any file (even the root) on the file system,
  1610.  * not the block special device name as in Solaris 1.
  1611.  * Thanks to veronica@solution.maths.unsw.edu.au who provided
  1612.  * the idea and the basis for this function.
  1613.  */
  1614.  
  1615. int quotactl(int cmd, char *special, uid_t uid, struct dqblk * addr)
  1616. {
  1617.     struct quotctl  op;
  1618.     int             fd = open(special, O_RDONLY);
  1619.  
  1620.     if ( fd < 0)
  1621.         return -1;
  1622.  
  1623.     op.op = cmd;
  1624.     op.uid = uid;
  1625.     op.addr = (caddr_t) addr;
  1626.  
  1627.     if (ioctl(fd, Q_QUOTACTL, &op) < 0) {
  1628.         close(fd);
  1629.         return -1;
  1630.     }
  1631.     close(fd);
  1632.     return (0);
  1633. }
  1634. #endif  /* USE_IOCTL */
  1635.  
  1636.  
  1637. void check_args( int nargs, char **argv)
  1638. {
  1639.     while ( --nargs)
  1640.     if ( strcmp( *++argv, "-t") == 0)
  1641.         Resrcs.show_titlebar = False;
  1642. }   
  1643.  
  1644.  
  1645. /**
  1646.     fatal: prints an error message and terminates program.
  1647. **/
  1648. void fatal( char *fmt, ...)
  1649. {
  1650.     va_list args;
  1651.  
  1652.     va_start( args, fmt);
  1653.     fprintf( stderr, "%s:", progname);
  1654.     vfprintf( stderr, fmt, args);
  1655.     putc( '\n', stderr);
  1656.     va_end( args);
  1657.     exit( 1);
  1658. }
  1659.  
  1660.  
  1661. /**
  1662.     warning: prints an warning message.
  1663. **/
  1664. void warning( char *fmt, ...)
  1665. {
  1666.     va_list args;
  1667.     
  1668.     va_start( args, fmt);
  1669.     fprintf( stderr, "%s:", progname);
  1670.     vfprintf( stderr, fmt, args);
  1671.     putc( '\n', stderr);
  1672.     va_end( args);
  1673. }
  1674.  
  1675.  
  1676. /**
  1677.     fget_line: get a line of characters from file fp
  1678. **/
  1679. int fget_line( char *s, int lim, FILE *fp)
  1680. {
  1681.    if ( fgets( s, lim, fp) == NULL)
  1682.       return ( EOF);
  1683.    else {
  1684.       s[ strlen( s) - 1] = '\0';
  1685.       return( strlen( s));
  1686.    }
  1687. }
  1688.  
  1689.  
  1690. /**
  1691.   searchfor: Searchs for a string within another string.
  1692.   **/
  1693. int searchfor( char *string, char *test)
  1694. {
  1695.     char *s;
  1696.     int   ltest;
  1697.     
  1698.     ltest   = strlen( test);
  1699.     s       = string;
  1700.     while (( s = strchr( s, *test)) != NULL) {
  1701.     if ( strlen( s) >= ltest)
  1702.         if ( strncmp( s, test, ltest) == 0)
  1703.         return( True);
  1704.     ++s;
  1705.     }
  1706.     return( False);
  1707. }
  1708.